#include "RendererParams.h"

using namespace Nezha;

typedef PMap<_string, RendererParamsDef> NamedRendererParams;
typedef PMap<RendererParamsType, RendererParamsDef> RPTRendererParams;
static NamedRendererParams gsRendererParamDefs_N;
static RPTRendererParams gsRendererParamDefs_RPT;

class RendererParamDefAutoReg
{
public:
	RendererParamDefAutoReg(const char* csName, RendererParamsType rpt, ShaderParamDataType spdt)
	{
		RendererParamsDef def(csName, rpt, spdt);
		gsRendererParamDefs_N.insert(MapPair<_string, RendererParamsDef>(csName, def));
		gsRendererParamDefs_RPT.insert(MapPair<RendererParamsType, RendererParamsDef>(rpt, def));
	}
};

#define RENDERER_PARAM_DEF(_name, spdt) static RendererParamDefAutoReg s_RPDAR##_name(#_name, _name, spdt);

RENDERER_PARAM_DEF(W_MATRIX, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(V_MATRIX, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(P_MATRIX, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(WV_MATRIX, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(VP_MATRIX, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(WVP_MATRIX, SPDT_FLOAT4X4);

// transpose
RENDERER_PARAM_DEF(W_MATRIX_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(V_MATRIX_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(P_MATRIX_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(WV_MATRIX_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(VP_MATRIX_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(WVP_MATRIX_T, SPDT_FLOAT4X4);

// inverse
RENDERER_PARAM_DEF(W_MATRIX_I, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(V_MATRIX_I, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(P_MATRIX_I, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(WV_MATRIX_I, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(VP_MATRIX_I, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(WVP_MATRIX_I, SPDT_FLOAT4X4);

// inverse transpose
RENDERER_PARAM_DEF(W_MATRIX_I_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(V_MATRIX_I_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(P_MATRIX_I_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(WV_MATRIX_I_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(VP_MATRIX_I_T, SPDT_FLOAT4X4);
RENDERER_PARAM_DEF(WVP_MATRIX_I_T, SPDT_FLOAT4X4);

// vec3 parameters
// camera
RENDERER_PARAM_DEF(CAM_LOCAL_POS, SPDT_FLOAT3);
RENDERER_PARAM_DEF(CAM_LOCAL_DIR, SPDT_FLOAT3);
RENDERER_PARAM_DEF(CAM_LOCAL_UP, SPDT_FLOAT3);
RENDERER_PARAM_DEF(CAM_LOCAL_RIGHT, SPDT_FLOAT3);
RENDERER_PARAM_DEF(CAM_WORLD_POS, SPDT_FLOAT3);
RENDERER_PARAM_DEF(CAM_WORLD_DIR, SPDT_FLOAT3);
RENDERER_PARAM_DEF(CAM_WORLD_UP, SPDT_FLOAT3);
RENDERER_PARAM_DEF(CAM_WORLD_RIGHT, SPDT_FLOAT3);

// projector
RENDERER_PARAM_DEF(PROJ_LOCAL_POS, SPDT_FLOAT3);
RENDERER_PARAM_DEF(PROJ_LOCAL_DIR, SPDT_FLOAT3);
RENDERER_PARAM_DEF(PROJ_LOCAL_UP, SPDT_FLOAT3);
RENDERER_PARAM_DEF(PROJ_LOCAL_RIGHT, SPDT_FLOAT3);
RENDERER_PARAM_DEF(PROJ_WORLD_POS, SPDT_FLOAT3);
RENDERER_PARAM_DEF(PROJ_WORLD_DIR, SPDT_FLOAT3);
RENDERER_PARAM_DEF(PROJ_WORLD_UP, SPDT_FLOAT3);
RENDERER_PARAM_DEF(PROJ_WORLD_RIGHT, SPDT_FLOAT3);

/** light
	spot cutoff (angle, cos, sin, exponent)
	attenuation (const, linear, quad, intensity)
	pos.a, dir.a, defines the ranges.
*/
RENDERER_PARAM_DEF(LIT0_LOCAL_POS, SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT0_LOCAL_DIR,  SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT0_WORLD_POS,  SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT0_WORLD_DIR, SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT0_COLOR, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT0_SPOTCUTOFF, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT0_ATTENUATION, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT1_LOCAL_POS, SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT1_LOCAL_DIR,  SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT1_WORLD_POS,  SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT1_WORLD_DIR, SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT1_COLOR, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT1_SPOTCUTOFF, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT1_ATTENUATION, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT2_LOCAL_POS, SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT2_LOCAL_DIR,  SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT2_WORLD_POS,  SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT2_WORLD_DIR, SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT2_COLOR, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT2_SPOTCUTOFF, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT2_ATTENUATION, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT3_LOCAL_POS, SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT3_LOCAL_DIR,  SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT3_WORLD_POS,  SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT3_WORLD_DIR, SPDT_FLOAT3);
RENDERER_PARAM_DEF(LIT3_COLOR, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT3_SPOTCUTOFF, SPDT_FLOAT4);
RENDERER_PARAM_DEF(LIT3_ATTENUATION, SPDT_FLOAT4);

RendererParam::RendererParam(RendererParamsType rpt)
	:mRendererParamType(rpt)
{

}

bool RendererParam::isLightingParam() const
{
	return mRendererParamType >= LIT0_LOCAL_POS && mRendererParamType <= LIT3_ATTENUATION;
}

u32 RendererParam::DetermineParamSize(RendererParamsType rpt)
{
	RPTRendererParams::iterator it = gsRendererParamDefs_RPT.find(rpt);

	if(it != gsRendererParamDefs_RPT.end())
	{
		return ShaderParameter::DataTypeSize(it->second.mDataType);
	}

	return 0;
}

ShaderParamDataType RendererParam::RPT2ShdParamDataType(RendererParamsType rpt)
{
	RPTRendererParams::iterator it = gsRendererParamDefs_RPT.find(rpt);

	if(it != gsRendererParamDefs_RPT.end())
	{
		return it->second.mDataType;
	}

	return SPDT_USER;
}

RendererParamsType RendererParam::NameToType(const _string& name)
{
	NamedRendererParams::iterator it = gsRendererParamDefs_N.find(name);

	if(it != gsRendererParamDefs_N.end())
	{
		return it->second.mRPType;
	}

	return RPT_UNKNOWN;
}